#ifndef OPTICAL_FLOW_PROCESSOR_H
#define OPTICAL_FLOW_PROCESSOR_H

#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/features2d/features2d.hpp>
//#include <opencv2/nonfree/nonfree.hpp>
#include <opencv2/calib3d/calib3d.hpp>
#include <opencv2/video/tracking.hpp>
#include <vector>
#include <jni.h>

#define OPTICAL_FLOW_WINSIZE 							21
#define OPTICAL_FLOW_MAX_FEATURES						500
#define OPTICAL_FLOW_RESET_THRESHOLD					25
#define OPTICAL_FLOW_CALC_RANSAC_THRESHOLD				10
#define OPTICAL_FLOW_MAX_RANSAC_ERROR					3.0f
#define OPTICAL_FLOW_MAX_RANSAC_TRY_COUNT				70

#define OPTICAL_FLOW_ACTION_CALC_FLOW_RANSAC_NODRAW		0x00
#define OPTICAL_FLOW_ACTION_CALC_FLOW_RANSAC			0x01
#define OPTICAL_FLOW_ACTION_CALC_FLOW_ONLY 				0x02
#define OPTICAL_FLOW_ACTION_FEATURES_ONLY				0x03
#define OPTICAL_FLOW_ACTION_PLAY_AROUND					0x0F

//TODO: merge later.
#define OPTICAL_FLOW_ACTION_CALC_SIFT_FEATURES			0x04
#define OPTICAL_FLOW_ACTION_CALC_FREAK_FEATURES			0x05

#define OPTICAL_FLOW_FEATURES_FAST						0x10
#define OPTICAL_FLOW_FEATURES_SIFT						0x11
#define OPTICAL_FLOW_FEATURES_ORB						0x12

#define OPTICAL_FLOW_DESCRIPTOR_DEFAULT					0x20
#define OPTICAL_FLOW_DESCRIPTOR_FREAK					0x21

using namespace std;
using namespace cv;

class OpticalFlowProcessor
{
	private:
	static OpticalFlowProcessor* ofp;
	static const double PI = 3.14159265358979323846;

	private:
	Size winSize;

	Mat* prevFrame;
	Mat* currFrame;
	vector<Point2f> lastFeatures;
	vector<Point2f> currFeatures;
	Point2f displacement;
	double orientation;
	Point frameSize;
	Point2f frameCentroid;

	vector<KeyPoint> oldKeyPoints;
	vector<KeyPoint> newKeyPoints;
	Mat oldDescriptors;
	Mat newDescriptors;

	vector<vector<KeyPoint> > allKeyPoints;
	vector<Mat> allDescriptors;



	private:
	OpticalFlowProcessor(int width, int height);
	~OpticalFlowProcessor();
	void DrawArrow(Mat* image, Point2f a, Point2f b, int thickness);

	public:
	void Process(int action, long long newFrameAddr, long long frameToDraw);
	double GetDisplacementX();
	double GetDisplacementY();
	double GetOrientation();

	public:
	static OpticalFlowProcessor* InitProcessor(int width, int height);
	static bool IsInitialized();
	static void Release();


};

#endif
